// Copyright(c) Sonosemi Medical Ltd. Embedded Software Team.
// Author: Zhang Yisong(zhangyisong@sonosemi.com)

#pragma once
#include "boost/mp11.hpp"
#include "boost/sml.hpp"
#include "etl/deque.h"
#include "etl/queue.h"
#include "etl/singleton.h"
#include "internal/active_concepts.hpp"
#include "internal/active_logging.hpp"
#include "internal/concepts/active_policy.hpp"
#include <type_traits>
namespace active {
namespace internal {

template <typename TConfig, concepts::Policable TPolicyList>
struct StateMachine {
  template <typename... Ts> using SmConfig = boost::sml::sm<TConfig, Ts...>;
  using Type = boost::mp11::mp_rename<TPolicyList, SmConfig>;
};

template <template <typename...> typename TList, typename... TPolicies>
constexpr auto Policies(TList<TPolicies...>) {
  return boost::mp11::mp_list<TPolicies...>{};
};
template <typename TConfig, concepts::Policable TPolicy>
using StateMachineType = StateMachine<TConfig, TPolicy>::Type;

template <concepts::Policable TPolicy>
using PolicyList = decltype(Policies(TPolicy{}));

template <size_t kQueueSize> struct DeferPolicy {
public:
  template <typename T> using Deque = etl::deque<T, kQueueSize>;
  template <typename T> using Queue = etl::queue<T, kQueueSize>;
  static constexpr auto policy = internal::Policy<boost::sml::defer_queue<Deque>,
                         boost::sml::process_queue<Queue>>{};
};

} // namespace internal
template <typename... Ts>
static auto constexpr policy = internal::Policy<Ts...>{};
template <size_t queue_size>
static auto constexpr deferable = internal::DeferPolicy<queue_size>::policy;
   

static auto constexpr testing = internal::Policy<boost::sml::testing>{};
static auto constexpr logging =
    internal::Policy<boost::sml::logger<active::internal::Logger>>{};
template <concepts::Policable... TPolicies>
static auto consteval Policy(TPolicies...) {
  using namespace boost::mp11;
  using Policies = mp_append<TPolicies...>;
  return Policies{};
}

} // namespace active